package za.org.jcicada.watchdog;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import za.org.jcicada.cfgmngr.ISystemObserver;
import za.org.jcicada.cfgmngr.ISystemSubject;
import za.org.jcicada.cfgmngr.SystemSetType;
import za.org.jcicada.cfgmngr.impl.CfgMngr;
import za.org.jcicada.cfgmngr.impl.DefaultSystemObserver;
import za.org.jcicada.cfgmngr.impl.SystemSubject;
import za.org.jcicada.cfgmngr.impl.SystemSubjectProxy;
import za.org.jcicada.confss.impl.ConfSS;
import za.org.jcicada.genss.ServiceURN;
import za.org.jcicada.genss.SystemURN;
import za.org.jcicada.genss.messages.Result;
import za.org.jcicada.genss.messages.SuccessCode;
import za.org.jcicada.genss.sensor.SensorURN;

public class Watchdog extends ConfSS {

	/** Logger object used for logging messages. */
	private static final Log logger = LogFactory.getLog(Watchdog.class);

 	/** Dynamic configuration object for this class, contents from CfgMngr. */
	private WatchdogDynamicConfiguration watchdogDynamic = new WatchdogDynamicConfiguration();
	
	/** Map of systems to watch and the corresponding objects */
	private Map<SystemURN, SystemWatchdog> systemWatchdogs = new HashMap<SystemURN, SystemWatchdog>();

	private ISystemSubject systemSubject = null;
	private ISystemObserver systemObserver;
	
	/**
	 * Constructor
	 * 
	 * @param systemURN
	 *            the name of this device proxy object
	 * @param uriCfgMngrLocation
	 *            the location of the CfgMngr
	 */
	public Watchdog(SystemURN systemURN, URI uriCfgMngrLocation) throws URISyntaxException {
		super(systemURN, uriCfgMngrLocation);
		systemObserver = new DefaultSystemObserver() {
			
			@Override
			public void informSystemEvent(SystemURN systemURN, SystemSetType type, Event event) {
				if (type == SystemSetType.REGISTERED) {
					SystemWatchdog systemWatchdog = systemWatchdogs.get(systemURN);
					if (systemWatchdog != null) {
						switch(event) {
						case REGISTERED:
							systemWatchdog.systemRegistered();
							break;
						case DEREGISTERED:
							systemWatchdog.systemDeregistered();
							break;
						}
					}
				}
			}

		};
	}

	public ISystemSubject getSystemSubject() {
		return systemSubject;
	}
	
	public Map<SystemURN, SystemWatchdog> getSystemWatchdogs() {
		return systemWatchdogs;
	}

	/**
	 * Do base class initialization then create and start a ping timer.
	 */
	@Override
	protected void duringInitialize() throws Exception {
		super.duringInitialize();
		systemWatchdogs.clear();
	}

	/**
	 * Shutdown first stops the ping timer, sets all the watchdog sensors to
	 * UNKNOWN then stops the ConfSS base object.
	 */
	@Override
	protected void duringShutdown() throws Exception {
		if (systemSubject != null) {
			systemSubject.informDisconnect(systemObserver);
		}
		for (SystemWatchdog watchdog : systemWatchdogs.values()) {
			watchdog.shutdown();
		}
		super.duringShutdown();
	}
	
	@Override
	public void replyGetConfiguration(Result result, Object configuration) {
		super.replyGetConfiguration(result, configuration);
		watchdogDynamic.loadProperties((Properties) configuration);

		// retrieve set of all systems to monitor from cfgmngr
		getConfigurationServer().requestSystemSet(this, SystemSetType.ENABLED);
	}

	public void replyLocateService(Result result, ServiceURN serviceURN, URI locationURI) {
		logger.info(String.format("Located %s at %s", serviceURN, locationURI));
		if (result.getCode() == SuccessCode.COMPLETE_SUCCESS) {
			if (serviceURN.getInterface().equals("systems")) {
				systemSubject = new SystemSubjectProxy(locationURI);
				systemSubject.requestAttach(systemObserver);
			}
		}
	}

	public void replySystemSet(Result result, SystemSetType type, Set<SystemURN> systemURNs) {
		logger.info(String.format("System set: %s", systemURNs));
		switch (type) {
		case ENABLED:
			for (SystemURN systemURN : systemURNs) {
				if (systemURN.isNodeProxy()) {
					try {
						SystemWatchdog systemWatchdog = new SystemWatchdog(getConfigurationServer(), systemURN, getTimer(), watchdogDynamic.pingPeriod_ms, watchdogDynamic.pingTimeout_ms, watchdogDynamic.watchdogStatusStrategy);
						systemWatchdogs.put(systemURN, systemWatchdog);
						addSensor(systemURN, systemWatchdog.getSensor());
					} catch (URISyntaxException ex) {
						logger.error(ex);
					}
				}
			}
			break;
		}
		try {
			ServiceURN serviceURN = new ServiceURN(new SystemURN(CfgMngr.SYSTEM_NAME), SystemSubject.URN_SERVICE);
			configurationServer.requestLocateService(this, serviceURN, "tcp");
		} catch (URISyntaxException e) {
			logger.error(e);
		}
	}

	public void replySensorSet(Result arg0, SystemURN arg1, Set<SensorURN> arg2) {
	}

	/**
	 * Main function takes no arguments. A cfgmngr knows what it subsystemURI
	 * will be since there can be only one!
	 * 
	 * @param args
	 *            the command line arguments
	 */
	public static void main(String args[]) {
		String[] confssArgs = { Watchdog.class.getCanonicalName(), args[0], args[1] };
		ConfSS.main(confssArgs);
	}

}
